package high.concurrent.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import high.concurrent.dto.MsgDto;
import high.concurrent.enums.MQConstant;
import high.concurrent.mapper.TxMsgMapper;
import high.concurrent.model.TxMsg;
import high.concurrent.service.TxMsgService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.loadbalancer.LoadBalancerClient;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.util.List;

/**
 * Author 黄保泽
 * 描述 :
 */
@Service
public class TxMsgServiceImpl implements TxMsgService {

    private final static Logger LOGGER = LoggerFactory.getLogger(TxMsgServiceImpl.class);

    @Autowired(required = false)
    private TxMsgMapper txMsgMapper;

    @Autowired
    private RabbitTemplate rabbitTemplate;

    @Autowired
    private RedisTemplate redisTemplate;

    /**
     * ribbon 负载均衡客户端
     */
    @Autowired
    private LoadBalancerClient loadBalancerClient;


    /**
     * 创建消息数据，并且状态默认是未发送
     */
    @Override
    public MsgDto createMsgDataByMsgService(MsgDto txMsgDTO) {

        LOGGER.info("进入createMsgDataByMsgService接口");

        // 创建消息对象
        TxMsg txMsg = new TxMsg();
        // dto赋值
        BeanUtils.copyProperties(txMsgDTO, txMsg);
        // 创建消息记录
        txMsgMapper.insert(txMsg);

        // 创建消息dto对象
        MsgDto rtnData = new MsgDto();
        // 给dto赋值
        BeanUtils.copyProperties(txMsg, rtnData);
        LOGGER.info("完成createMsgDataByMsgService接口");

        return rtnData;
    }

    /**
     * 根据msgId更改消息数据状态为已发送
     * @param msgId 消息id(全局唯一id)
     */
    @Override
    public void updateMsgDataByMsgService(String msgId) {

        LOGGER.info("进入updateMsgDataByMsgService接口");

        // 创建json数据变量，存储转型后的对象
        String jsonData = "";
        // 创建路由名
        String routingKey = "";
        // 更改消息数据状态为已发送
        txMsgMapper.update(null, new UpdateWrapper<TxMsg>()
                .eq("msg_id", msgId)
                .eq("del_flg", 0)
                .set("status", 1));

        // 并将消息发送到rabbitmq中，首先从消息表中查询消息内容
        TxMsg txMsg = txMsgMapper.selectOne(new QueryWrapper<TxMsg>()
                .eq("msg_id", msgId)
                .eq("del_flg", 0));

        // 如果查到消息内容不为空
        if(txMsg != null) {
            // 把对象转换为json
            jsonData = txMsg.getJsonMsg();
            // 取出对象中的路由名
            routingKey = txMsg.getRoutingKey();
        }
        // 发送消息到MQ（订单+积分服务通用）
        rabbitTemplate.convertAndSend(MQConstant.EXCHANGE_NAME, routingKey, jsonData);

        LOGGER.info("完成updateMsgDataByMsgService接口");
    }

    /**
     * 通知消息服务，删除对应订单的消息数据
     * @param txMsgDTO
     */
    @Override
    public void delMsgDataByOrderNo(MsgDto txMsgDTO) {

        LOGGER.info("进入delMsgDataByOrderNo接口");
        txMsgMapper.deleteById(txMsgDTO.getMsgId());
        LOGGER.info("完成delMsgDataByOrderNo接口");
    }

    /**
     * 消息服务定期轮询，过期的“已发送”消息（过期一般是根据业务规则来自行调整，例如2min）（查已发送的定时器）
     * @param verdueTime 轮询间隔
     * @return
     */
    @Override
    public List<TxMsg> selectOverdueMsgBySend(int verdueTime) {

        LOGGER.info("进入selectOverdueMsgBySend接口");

        // 查看消息
        List<TxMsg> txMsgs = this.txMsgMapper.selectOverdueMsg(1, verdueTime);

        LOGGER.info("完成selectOverdueMsgBySend接口");

        return txMsgs;

    }

    /**
     * 定时器轮询过期“待发送”状态的消息（过期消息一般是根据业务规则自行调整，例如 2min）（查待发送的定时器）
     * @param verdueTime 轮询间隔
     * @return
     */
    @Override
    public List<TxMsg> selectOverdueMsgByNotSend(int verdueTime) {

        LOGGER.info("进入selectOverdueMsgByNotSend接口");

        // 查看消息
        List<TxMsg> txMsgs = this.txMsgMapper.selectOverdueMsg(0, verdueTime);

        LOGGER.info("完成selectOverdueMsgByNotSend接口");

        return txMsgs;

    }

}
